package apibasej.xml;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.logging.Level;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import apibasej.basic.config.ConfigManager;
import apibasej.basic.exception.APIBaseRuntimeException;
/**
 * http://code.google.com/p/apibasej/
 * 
 * @author Julio Azevedo Lessa - apibasej@gmail.com
 * 
 */
public class DocXML extends ConfigManager{

	
	private Document doc = null;

	public ElemXML getElemRoot(){
		if(doc.getDocumentElement()==null) return null;
		return new ElemXML(doc.getDocumentElement(),this);
	}

	public ElemXML createRoot(String nameRoot){
		Element root = doc.createElement(nameRoot);
		doc.appendChild(root);
		return new ElemXML( root,this );
	}

	public DocXML(File f) throws ParserConfigurationException, SAXException, IOException {
		doc = getDocFromFile( f );
	}

	public DocXML(String body) throws ParserConfigurationException, SAXException, IOException {
		doc = getDocFromString( body );
	}
	public DocXML() throws ParserConfigurationException, SAXException, IOException {
		doc = getDocFromString( null );
	}

	public Document getDocFromFile(File f) throws ParserConfigurationException, SAXException, IOException{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = null;
		doc = db.parse( f );
		return doc;
	}

	public Document getDocFromString(String body) throws ParserConfigurationException, SAXException, IOException{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = null;
		if(body!=null) {
			doc = db.parse( new ByteArrayInputStream(body.getBytes(getProp(CHARSET))) );
		} else {
			doc = db.newDocument();
		}
		return doc;
	}

	/*
	public void saveDoc(String path) throws IOException{
		XMLSerializer serializer = new XMLSerializer ( new FileWriter( path ), getFormatDefault());
		serializer.serialize(doc);
	}

	private OutputFormat getFormatDefault(){
		OutputFormat format = new OutputFormat(doc);
		format.setLineSeparator(LineSeparator.Windows);
		format.setIndenting(true);
		format.setIndent(4);
		format.setEncoding(getConfig().getCharset());
		format.setLineWidth(0);
		//format.setPreserveSpace(true);
		return format;
	}
	*/
	
	public String getStringXML() throws TransformerException {
		return getStringXML(doc);
	}
	@Override
	public String toString() {
		try {
			return getStringXML();
		} catch (TransformerException e) {
			throw new APIBaseRuntimeException("Erros on generate string XML",e);
		}
	}
	
	public String getStringXML(Node node) throws TransformerException{
		
		/*
		try {
			System.out.println("######################################aaaaa");
			JAXBContext context = JAXBContext.newInstance(Teste.class);
			Marshaller marshaller = context.createMarshaller();
			marshaller.marshal(node, System.out);
			System.out.println("######################################bbbbb");
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		*/
		
		/*
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		XMLSerializer serializer = new XMLSerializer(os,getFormatDefault());
		serializer.serialize(doc);
		return os.toString();
		*/
		
		TransformerFactory tFactory = TransformerFactory.newInstance(); 
		//Config.getConfigDefault().getLogger().fine("tFactory>"+tFactory.getClass().getName());
		/* VER OPÇÃO DE SETAR ESTES PARAMETROS DEPOIS !!! SEPARADO !!!!
		try{
			 tFactory.setAttribute("indent-number", 2);  
		}catch (Throwable e) {
			getConfig().getLogger().log(Level.WARNING,"Error on set attribute 'indent-number'",e);
		}
		*/
		Transformer transformer = tFactory.newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		transformer.setOutputProperty(OutputKeys.ENCODING, getProp(CHARSET));
		try{
			transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
		}catch (Throwable e) {
			//getConfig().getLogger().log(Level.WARNING,"FAIL ON INDENT XML: transformer.setOutputProperty(\"{http://xml.apache.org/xslt}indent-amount\", \"2\")",e);
			logDef(Level.SEVERE,"FAIL ON INDENT XML: transformer.setOutputProperty(\"{http://xml.apache.org/xslt}indent-amount\", \"2\"). Error: "+e,e);
		}
		//transformer.setOutputProperty(OutputKeys.STANDALONE, "no");// standalone: O elemento independente XML define a existência de um DTD definido externamente
		//transformer.setOutputProperty(OutputKeys.METHOD, "xml");// já é default
		
		//initialize StreamResult with File object to save to file
		//Result result = new  StreamResult(new OutputStreamWriter(os,"UTF-8"));  
		StreamResult result = new StreamResult(new StringWriter());
		DOMSource source = new DOMSource(node);
		transformer.transform(source, result);

		return result.getWriter().toString();
	}
	
	
	/*
	// ??? NEM SEI PRA QUE SERVE
	public static Document getDocPelaURI(String uri) throws ClassCastException, ClassNotFoundException, InstantiationException, IllegalAccessException {
		System.setProperty(DOMImplementationRegistry.PROPERTY, "org.apache.xerces.dom.DOMImplementationSourceImpl");
		DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
		DOMImplementationLS impl = (DOMImplementationLS)registry.getDOMImplementation("LS");
		LSParser builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
		Document document = builder.parseURI( uri ); 
		return document;
	}*/

	public Document getDoc() {
		return doc;
	}



}
